<?php
// +----------------------------------------------------------------------
// | IPHP
// +----------------------------------------------------------------------
// | This is an open source and simple PHP FrameWork.
// +----------------------------------------------------------------------
// | $Id$
// +----------------------------------------------------------------------


// 模板引擎
namespace IPHP\Core;
use IPHP\Core\Storage;

class View {
    protected $fileName;
    protected $cacheFile;

    public function __construct($fileName,$cacheFile) {
        $this->fileName = $fileName;
        $this->cacheFile = $cacheFile;
    }

    /**
     * 解析模板
     * @param  [type] $fileName  原始模板路径
     * @param  [type] $cacheFile 编译后模板路径
     * @return [type]            [description]
     */
    public function pareseTpl($fileName, $cacheFile) {
        $html = file_get_contents($fileName);
        $html = $this->_tplRule1($html);
        $this->_putContent($cacheFile,$html);
    }

    /**
     * 模板标签语法解析1
     * @param  [type] $html [description]
     * @return [type]       [description]
     */
    private function _tplRule1($html) {
        // 解析模板标签
        // 去掉注释标签
        $html = str_replace(array("<!--{","}-->"), array("{","}"), $html);
        // 点语法支持        
        preg_match_all("/\{\\\$(\w*)\.(\w+|\d+)\}/iUs", $html, $match);
        $pointerVals = array();
        if($match[0] && is_array($match[0])) {
            foreach ($match[0] as $key => $val) {
                $val = trim($val,'{,},$');
                $tmp = explode('.', $val);
                $nt = '$';
                for($i = 0; $i<count($tmp); $i++) {
                    if($i == 0) {
                        $nt .= $tmp[$i];
                    } else {
                        $nt .= '[\''.$tmp[$i].'\']';
                    }
                }
                $pointerVals[] = '{'.$nt.'}';                
            }
        }
        $html = str_replace($match[0], $pointerVals, $html);
        $html = preg_replace("/\{\\\$get(\w*)\}/iUs", "<?php echo \$_GET\\1; ?>", $html);
        $html = preg_replace("/\{\\\$post(\w*)\}/iUs", "<?php echo \$_POST\\1; ?>", $html);

        // 设置变量标签
        $html = preg_replace("/\{set(.*)\}/iUs", "<?php \\1 ?>", $html); 
        // 输出变量标签
        $html = preg_replace("/\{(\\\$.*)\}/iUs", "<?php echo \\1; ?>", $html);
        // 输出常量标签
        $html = preg_replace("/\{const(.*)\}/iUs", "<?php echo \\1; ?>", $html);
        // if标签
        $html = preg_replace("/\{if(.*)\}/iUs", "<?php if(\\1) { ?>", $html);
        $html = preg_replace("/\{else.*\}/iUs", "<?php } else { ?>", $html);
        $html = preg_replace("/\{elseif(.*)\}/iUs", "<?php } elseif(\\1) { ?>", $html);
        $html = preg_replace("/\{\/if\}/iUs", "<?php } ?>", $html);
        $html = preg_replace("/\{\break\}/iUs", "<?php break; ?>", $html);
        $html = preg_replace("/\{\continue\}/iUs", "<?php continue; ?>", $html);
        // loop标签
        $html = preg_replace("/\{loop.*(\\\$\w+\b).*(\\\$.*)\}/iUs", "<?php foreach (\\1 as \\2) { ?>", $html);
        $html = preg_replace("/\{\/loop\}/iUs", "<?php } ?>", $html);
        // foreach标签,用来替代loop
        $html = preg_replace("/\{foreach.*(\\\$\w+\b).*(\\\$.*)\}/iUs", "<?php foreach (\\1 as \\2) { ?>", $html);
        $html = preg_replace("/\{\/foreach\}/iUs", "<?php } ?>", $html);
        // for标签
        $html = preg_replace("/\{for(.*)\}/iUs", "<?php for(\\1) { ?>", $html);
        $html = preg_replace("/\{\/for\}/iUs", "<?php } ?>", $html);
        // eval 标签
        $html = preg_replace("/\{eval(.*)\}/iUs", "<?php \\1 ?>", $html);

        // include 标签, 支持嵌套包含
        preg_match_all("/\{include\s[\"|](.*)[\"|\']\}/iUs", $html, $files);

        if($files[1]) {
            foreach ($files[1] as $key => $val) {
                $tplfile = VIEW_PATH.$val.TEMPLATE_SUFFIX;
                $tmp = $this->getCacheTpl($val);

                $this->checkTpl($tplfile,$tmp);
                
                if(IS_SAE) {
                    $html = preg_replace("/\{include\s[\"|]".preg_quote($val,"/")."[\"|\']\}/iUs", "SAETPL".$tmp."SAETPLEND", $html);
                } else {
                    $html = preg_replace("/\{include\s[\"|]".preg_quote($val,"/")."[\"|\']\}/iUs", "<?php include '".$tmp."'; ?>", $html);
                }

                
            }
        }

        // 解析模板常量
        // 目前支持的 
        // __STATIC__   __DATA__  __IMG__  __CSS__   __JS__   __PUBLIC__
        $html = preg_replace("/__STATIC__\//iUs",   "<?php echo __STATIC__ ?>", $html); 
        $html = preg_replace("/__DATA__\//iUs",     "<?php echo __DATA__ ?>",   $html); 
        $html = preg_replace("/__IMG__\//iUs",      "<?php echo __IMG__ ?>",    $html); 
        $html = preg_replace("/__CSS__\//iUs",      "<?php echo __CSS__ ?>",    $html); 
        $html = preg_replace("/__JS__\//iUs",       "<?php echo __JS__ ?>",     $html); 
        $html = preg_replace("/__PUBLIC__\//iUs",   "<?php echo __PUBLIC__ ?>", $html); 

        return $html;
    }

    /**
     * 检查模板缓存
     * @param  string $fileName  原始模板路径
     * @param  string $cacheFile 缓存模板路径
     * @return [type]            [description]
     */
    public function checkTpl($fileName="", $cacheFile="") {
        $fn = $fileName ? $fileName : $this->fileName;
        $cf = $cacheFile ? $cacheFile : $this->cacheFile;

        // $this->checkIncludeTpl($fn);

        if(!$fn) return false;
        if(IS_SAE) $cf = basename($cf);

        // 检查是否需要重新编译模板
        Storage::init();
        $cinfo = Storage::info($cf);
        if(!Storage::exists($cf) || filemtime($fn) > $cinfo['mtime']) {
            Storage::delete($cf);
            $this->pareseTpl($fn,$cf);
        }
        
        return true;
    }

    /**
     * 检查包含胡模板
     * @return [type] [description]
     */
    public function checkIncludeTpl($tplFileName) {
        $html = file_get_contents($tplFileName);
        // include 标签, 支持嵌套包含
        preg_match_all("/\{include\s[\"|](.*)[\"|\']\}/iUs", $html, $files);

        if($files[1]) {
            foreach ($files[1] as $key => $val) {
                $tplfile = VIEW_PATH.$val.TEMPLATE_SUFFIX;
                $tmp = $this->getCacheTpl($val);
                $this->checkTpl($tplfile,$tmp);
            }
        }
    }


    /**
     * 获取编译后的模板路径
     * @param  [type] $tplFileName [description]
     * @return [type]              [description]
     */
    static function getCacheTpl($tplFileName) {
        if(!$tplFileName) {
            $tplname = CONTROLLER_NAME.'/'.ACTION_NAME.TEMPLATE_SUFFIX;
        } else {
            $tplname = VIEW_PATH.$tplFileName;
        }
        $cacheTplFile = CACHE_PATH.'Template/tpl_'.md5($tplname).'.php';
        return $cacheTplFile;
    }

    /**
     * 写入内容到缓存目录
     * @return [type] [description]
     */
    private function _putContent($cacheFile,$replacedContent) {
        $dir = CACHE_PATH.'Template/';

        Storage::init();
        Storage::set($dir,$cacheFile,$replacedContent);
    }

    /**
     * 输出模板
     * @return [type] [description]
     */
    public function display($valobj) {
        $vars = get_object_vars($valobj);
        if($vars) extract($vars,EXTR_OVERWRITE);

        Storage::init();
        $content = Storage::get($this->cacheFile);

        if(IS_SAE) {
            $content = $this->saereplace($content);
        }

        ob_start();
        ob_implicit_flush(0);  
        eval('?>'.$content);

        $html = ob_get_clean();
        echo $html;
    }

    public function saereplace($html) {
        preg_match_all("/SAETPL(.*)SAETPLEND/iUs", $html, $files);

        $subtpl = array();
        if($files[1]) {
            foreach ($files[1] as $key => $val) {
                Storage::init();
                $subtpl[] = Storage::get($val);

            }
            $html = str_replace($files[0], $subtpl, $html);
            $html = $this->saereplace($html);
        }        
        return $html;
    }
}